<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Catalog Browser</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link
        href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900&display=swap"
        rel="stylesheet">
    <link rel="stylesheet"
        href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-G7SXDJEWXV"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'G-G7SXDJEWXV');
    </script>
    <style>
        body {
            font-family: "Poppins", sans-serif;
            padding-left: 1rem;
            padding-right: 1rem;
        }

        body.dark {
            background-color: #1a202c;
            color: #cbd5e0;
        }

        .dark input[type="search"] {
            background-color: #2d3748;
            color: #cbd5e0;
            border-color: #4a5568;
        }

        .dark select {
            background-color: #2d3748;
            color: #cbd5e0;
            border-color: #4a5568;
        }

        .dark header {
            background-color: #2d3748;
        }

        .dark #dataset-count {
            color: #cbd5e0;
        }

        .dark .filter-panel {
            background-color: #2d3748;
            border-color: #4a5568;
        }

        .btn {
            display: inline-block;
            border-radius: 9999px;
            padding: 0.25rem 0.5rem;
            text-align: center;
            cursor: pointer;
            transition: background-color 0.2s, transform 0.2s;
            white-space: nowrap;
        }

        .btn:hover {
            background-color: #2d3748;
            color: #fff;
            transform: scale(1.05);
        }

        input[type="search"] {
            border-radius: 9999px;
            margin-right: 1rem;
        }

        .grid-view {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
            gap: 1.5rem;
        }

        .list-view {
            display: flex;
            flex-direction: column;
            gap: 0.75rem;
        }

        .dataset-card {
            padding: 1rem;
            height: 100%;
            display: flex;
            flex-direction: column;
        }

        /* Fixed height elements for consistent card sizing */
        .card-title {
            height: 3rem;
            /* Fixed height for title - accommodates 2 lines */
            overflow: hidden;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            margin-bottom: 0.5rem;
        }

        .card-thematic {
            height: 1.5rem;
            /* Fixed height for thematic group */
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .card-image-container {
            aspect-ratio: 1/1;
            width: 100%;
            max-width: 16rem;
            /* 64 * 0.25rem = 16rem */
            margin: 0 auto;
            position: relative;
            overflow: hidden;
            border-radius: 0.375rem;
        }

        .card-buttons {
            height: 2.5rem;
            /* Fixed height for buttons */
            display: flex;
            gap: 0.5rem;
            justify-content: space-evenly;
            margin: 0.75rem 0;
        }

        .card-tags {
            height: 4.5rem;
            /* Fixed height for tags area - can fit 2 rows of tags */
            overflow: hidden;
        }

        .list-item {
            padding: 1rem;
            display: grid;
            grid-template-columns: 80px 1fr auto;
            align-items: center;
            gap: 1rem;
        }

        .tags-container {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
        }

        .tag {
            background-color: #e2e8f0;
            padding: 0.2rem 0.5rem;
            border-radius: 0.25rem;
            font-size: 0.75rem;
            transition: all 0.2s;
            white-space: nowrap;
            display: inline-block;
        }

        .tag:hover {
            background-color: #3182ce;
            color: white;
            transform: translateY(-1px);
        }

        .dark .tag {
            background-color: #4a5568;
        }

        .dark .tag:hover {
            background-color: #4299e1;
        }

        #loading-spinner {
            display: none;
            width: 50px;
            height: 50px;
            border: 5px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top-color: #3498db;
            animation: spin 1s ease-in-out infinite;
            margin: 20px auto;
        }

        @keyframes spin {
            to {
                transform: rotate(360deg);
            }
        }

        .dark #loading-spinner {
            border-color: rgba(255, 255, 255, 0.1);
            border-top-color: #3498db;
        }

        .lazy-image {
            transition: opacity 0.3s;
            opacity: 0;
            object-fit: cover;
            width: 100%;
            height: 100%;
            position: absolute;
            inset: 0;
        }

        .lazy-image.loaded {
            opacity: 1;
        }

        #pagination {
            display: flex;
            justify-content: center;
            margin-top: 2rem;
            gap: 0.5rem;
        }

        #pagination button {
            padding: 0.5rem 1rem;
            border: 1px solid #e2e8f0;
            border-radius: 0.25rem;
            margin: 0 0.15rem;
            background-color: white;
            min-width: 2.5rem;
            transition: all 0.2s;
        }

        #pagination button:hover:not(:disabled) {
            background-color: #edf2f7;
            transform: translateY(-2px);
        }

        .dark #pagination button {
            background-color: #2d3748;
            border-color: #4a5568;
        }

        .dark #pagination button:hover:not(:disabled) {
            background-color: #4a5568;
        }

        #pagination button.active {
            background-color: #3182ce;
            color: white;
            font-weight: bold;
        }

        /* Filter Panel Styles */
        .filter-panel {
            background-color: white;
            border: 1px solid #e2e8f0;
            border-radius: 0.5rem;
            padding: 1rem;
            margin-bottom: 1rem;
            transition: max-height 0.3s ease-in-out, opacity 0.3s;
        }

        .filter-panel.collapsed {
            max-height: 0;
            opacity: 0;
            overflow: hidden;
            padding: 0;
            margin: 0;
            border: none;
        }

        .filter-section {
            margin-bottom: 1rem;
        }

        .filter-section h3 {
            font-weight: 600;
            margin-bottom: 0.5rem;
        }

        .filter-options {
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
            margin-top: 0.5rem;
        }

        .filter-checkbox {
            display: flex;
            align-items: center;
            margin-right: 1rem;
        }

        .filter-checkbox input {
            margin-right: 0.25rem;
        }

        /* View Toggle Styles */
        .view-toggle {
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }

        .toggle-btn {
            background-color: #e2e8f0;
            padding: 0.25rem 0.5rem;
            border-radius: 0.25rem;
            cursor: pointer;
            transition: all 0.2s;
            display: flex;
            align-items: center;
            gap: 0.25rem;
        }

        .toggle-btn.active {
            background-color: #3182ce;
            color: white;
        }

        .dark .toggle-btn {
            background-color: #4a5568;
        }

        .dark .toggle-btn.active {
            background-color: #4299e1;
        }

        /* Controls Bar */
        .controls-bar {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 1rem;
            flex-wrap: wrap;
            gap: 1rem;
        }

        .sort-control {
            display: flex;
            align-items: center;
            gap: 0.5rem;
        }

        select {
            padding: 0.375rem 2.25rem 0.375rem 0.75rem;
            border: 1px solid #d1d5db;
            border-radius: 0.25rem;
            appearance: none;
            background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
            background-position: right 0.5rem center;
            background-repeat: no-repeat;
            background-size: 1.5em 1.5em;
        }

        /* Search History Dropdown Styles */
        .search-container {
            position: relative;
            display: flex;
            align-items: center;
            width: 100%;
            max-width: 400px;
        }

        .search-history-dropdown {
            position: absolute;
            top: 100%;
            left: 0;
            right: 0;
            z-index: 100;
            background-color: white;
            border: 1px solid #e2e8f0;
            border-radius: 0.5rem;
            max-height: 300px;
            overflow-y: auto;
            display: none;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        .dark .search-history-dropdown {
            background-color: #2d3748;
            border-color: #4a5568;
        }

        .search-history-item {
            padding: 0.75rem 1rem;
            cursor: pointer;
            transition: background-color 0.2s;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .search-history-item:hover {
            background-color: #f7fafc;
        }

        .dark .search-history-item:hover {
            background-color: #4a5568;
        }

        .search-history-item .history-text {
            flex-grow: 1;
        }

        .search-history-item .history-time {
            color: #718096;
            font-size: 0.75rem;
            margin-left: 0.5rem;
        }

        .dark .search-history-item .history-time {
            color: #a0aec0;
        }

        .search-history-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 0.75rem 1rem;
            border-bottom: 1px solid #e2e8f0;
        }

        .dark .search-history-header {
            border-color: #4a5568;
        }

        .clear-history-btn {
            font-size: 0.875rem;
            color: #e53e3e;
            cursor: pointer;
            transition: all 0.2s;
            padding: 0.25rem 0.5rem;
            border-radius: 0.25rem;
        }

        .clear-history-btn:hover {
            background-color: #FED7D7;
        }

        .dark .clear-history-btn {
            color: #FC8181;
        }

        .dark .clear-history-btn:hover {
            background-color: rgba(252, 129, 129, 0.2);
        }

        .search-history-empty {
            padding: 1rem;
            text-align: center;
            color: #718096;
        }

        .dark .search-history-empty {
            color: #a0aec0;
        }

        .history-icon {
            margin-left: 0.5rem;
            cursor: pointer;
            transition: all 0.2s;
        }

        .history-icon:hover {
            transform: scale(1.1);
        }

        /* Catalog Type Icon */
        .catalog-icon {
            position: absolute;
            top: 5px;
            right: 5px;
            width: 24px;
            height: 24px;
            z-index: 10;
            border-radius: 50%;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 2px;
        }

        .dark .catalog-icon {
            background-color: rgba(45, 55, 72, 0.8);
        }

        /* Radio button styling for catalog filter */
        .catalog-radio-group {
            display: flex;
            gap: 1rem;
        }

        .catalog-radio-option {
            display: flex;
            align-items: center;
            gap: 0.25rem;
        }

        .catalog-radio-option input[type="radio"] {
            margin-right: 0.25rem;
        }

        .catalog-count-badge {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            padding: 0.125rem 0.375rem;
            font-size: 0.75rem;
            border-radius: 9999px;
            background-color: #e2e8f0;
            margin-left: 0.5rem;
        }


        .dark .catalog-count-badge {
            background-color: #4a5568;
        }

        /* Add the new CSS here, right before the closing style tag */
        /* Updated CSS for better tag handling */
        .card-tags {
            min-height: 4.5rem; /* Minimum height but can grow if needed */
            max-height: 4.5rem; /* Maximum height to maintain consistency */
            overflow: hidden;
            position: relative;
        }

        /* Add a fade-out effect for overflowing tags */
        .card-tags::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 1.5rem;
            background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0.9));
            pointer-events: none; /* Allow clicks to pass through */
        }

        .dark .card-tags::after {
            background: linear-gradient(to bottom, rgba(26,32,44,0), rgba(26,32,44,0.9));
        }

        /* Make tags more compact */
        .tag {
            background-color: #e2e8f0;
            padding: 0.15rem 0.4rem;
            border-radius: 0.25rem;
            font-size: 0.7rem;
            transition: all 0.2s;
            white-space: nowrap;
            display: inline-block;
            margin: 0.15rem;
        }

        /* Updated tags container */
        .tags-container {
            display: flex;
            flex-wrap: wrap;
            gap: 0.3rem;
            padding-bottom: 0.5rem; /* Add space for the gradient fade */
        }

        /* "More tags" indicator that stays at the bottom right */
        .more-tags-indicator {
            position: absolute;
            bottom: 0.3rem;
            right: 0.3rem;
            background-color: #4a5568;
            color: white;
            padding: 0.1rem 0.3rem;
            border-radius: 0.25rem;
            font-size: 0.65rem;
            z-index: 5; /* Above the gradient */
        }

        .dark .more-tags-indicator {
            background-color: #718096;
        }

        /* Make list view tags more compact */
        .list-tags {
            display: flex;
            flex-wrap: wrap;
            gap: 0.3rem;
            max-width: 100%;
        }

        .list-tags .tag {
            margin: 0.1rem;
        }

        /* List view specific styling */
        .list-title {
            font-weight: 500;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            max-width: 100%;
        }

        .list-thematic {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .list-tags {
            display: flex;
            flex-wrap: wrap;
            gap: 0.375rem;
            max-width: 100%;
        }
    </style>
</head>

<body class="min-h-screen">
    <header class="sticky top-0 z-50 w-full border-b bg-white dark:bg-gray-800">
        <div class="container mx-auto p-4 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <img src="https://i.imgur.com/FYPcTFF.png" alt="Logo" class="h-12">
                <h1 class="text-lg font-bold">Catalog Browser</h1>
            </div>
            <div class="flex items-center flex-grow justify-center max-w-xl">
                <div class="search-container">
                    <input type="search" id="search" placeholder="Search datasets..." class="p-2 rounded border w-full">
                    <button id="history-toggle" class="history-icon">
                        <span class="material-symbols-outlined">history</span>
                    </button>
                    <div class="search-history-dropdown" id="search-history-dropdown">
                        <div class="search-history-header">
                            <span class="font-medium">Recent Searches</span>
                            <button id="clear-history" class="clear-history-btn">Clear All</button>
                        </div>
                        <div id="search-history-list">
                            <!-- Search history items will be populated here -->
                            <div class="search-history-empty">No recent searches</div>
                        </div>
                    </div>
                </div>
                <span id="dataset-count" class="text-gray-700 dark:text-gray-300 ml-2">0 datasets</span>
                <button id="filter-toggle" class="p-2 ml-2">
                    <span class="material-symbols-outlined">filter_alt</span>
                </button>
            </div>
            <button id="theme-toggle" class="p-2">
                <span class="material-symbols-outlined" id="theme-icon">light_mode</span>
            </button>
        </div>
    </header>
    <main class="container mx-auto py-6">
        <!-- Filter Panel -->
        <div id="filter-panel" class="filter-panel collapsed">
            <!-- Catalog Filter Section -->
            <div class="filter-section">
                <h3>Filter by Catalog Type</h3>
                <div id="catalog-filters" class="catalog-radio-group mt-2">
                    <div class="catalog-radio-option">
                        <input type="radio" id="catalog-all" name="catalog-type" value="all" checked>
                        <label for="catalog-all">All Catalogs</label>
                        <span id="all-count" class="catalog-count-badge">0</span>
                    </div>
                    <div class="catalog-radio-option">
                        <input type="radio" id="catalog-main" name="catalog-type" value="main">
                        <label for="catalog-main">Main Catalog</label>
                        <span id="main-count" class="catalog-count-badge">0</span>
                    </div>
                    <div class="catalog-radio-option">
                        <input type="radio" id="catalog-community" name="catalog-type" value="community">
                        <label for="catalog-community">Community Catalog</label>
                        <span id="community-count" class="catalog-count-badge">0</span>
                    </div>
                </div>
            </div>

            <div class="filter-section">
                <h3>Filter by Thematic Group</h3>
                <div id="thematic-filters" class="filter-options">
                    <!-- Thematic groups will be dynamically added here -->
                </div>
            </div>
            <div class="filter-section">
                <h3>Filter by Popular Tags</h3>
                <div id="tag-filters" class="filter-options">
                    <!-- Tags will be dynamically added here -->
                </div>
            </div>
        </div>
        <!-- Controls Bar -->
        <div class="controls-bar">
            <div class="view-toggle">
                <button id="grid-view-btn" class="toggle-btn active">
                    <span class="material-symbols-outlined">grid_view</span>
                    <span>Grid</span>
                </button>
                <button id="list-view-btn" class="toggle-btn">
                    <span class="material-symbols-outlined">view_list</span>
                    <span>List</span>
                </button>
            </div>
            <div class="sort-control">
                <label for="sort-select">Sort by:</label>
                <select id="sort-select">
                    <option value="random">Random</option>
                    <option value="title-asc">Title A-Z</option>
                    <option value="title-desc">Title Z-A</option>
                    <option value="group">Thematic Group</option>
                </select>
            </div>
        </div>
        <div id="loading-spinner"></div>
        <div id="dataset-container" class="grid-view">
            <!-- Datasets will be dynamically loaded here -->
        </div>
        <div id="pagination" class="mt-8"></div>
    </main>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const datasetContainer = document.getElementById('dataset-container');
            const searchInput = document.getElementById('search');
            const themeToggle = document.getElementById('theme-toggle');
            const themeIcon = document.getElementById('theme-icon');
            const datasetCount = document.getElementById('dataset-count');
            const loadingSpinner = document.getElementById('loading-spinner');
            const paginationContainer = document.getElementById('pagination');
            const filterPanel = document.getElementById('filter-panel');
            const filterToggle = document.getElementById('filter-toggle');
            const thematicFilters = document.getElementById('thematic-filters');
            const tagFilters = document.getElementById('tag-filters');
            const gridViewBtn = document.getElementById('grid-view-btn');
            const listViewBtn = document.getElementById('list-view-btn');
            const sortSelect = document.getElementById('sort-select');
            const historyToggle = document.getElementById('history-toggle');
            const searchHistoryDropdown = document.getElementById('search-history-dropdown');
            const searchHistoryList = document.getElementById('search-history-list');
            const clearHistoryBtn = document.getElementById('clear-history');
            const catalogFilterInputs = document.querySelectorAll('input[name="catalog-type"]');
            const allCountBadge = document.getElementById('all-count');
            const mainCountBadge = document.getElementById('main-count');
            const communityCountBadge = document.getElementById('community-count');

            let datasets = [];
            let mainCatalogDatasets = [];
            let communityCatalogDatasets = [];
            let filteredDatasets = [];
            let currentPage = 1;
            let currentView = 'grid';
            const itemsPerPage = 12;
            let searchTimeout = null;
            let activeThematicFilters = [];
            let activeTagFilters = [];
            let activeCatalogFilter = 'all';
            let allThematicGroups = [];
            let allTags = [];
            let searchHistory = [];
            const MAX_HISTORY_ITEMS = 10;

            // URLs for the catalogs
            const mainCatalogUrl = 'https://raw.githubusercontent.com/samapriya/ee-catalog-jsons/refs/heads/main/gee_catalog_formatted.json';
            const communityCatalogUrl = 'https://raw.githubusercontent.com/samapriya/ee-catalog-jsons/refs/heads/main/community_datasets.json';

            // Add a consistent fallback for images that fail to load
            function createFallbackImageUrl(width, height) {
                // Return a placeholder image URL with the given dimensions
                return `/api/placeholder/${width}/${height}`;
            }

            // Pre-load images when switching views
            function preloadImagesForView() {
                // Reset lazy loading when changing views
                initLazyLoading();
            }

            // Storage helper that falls back to memory when localStorage is unavailable
            const storage = {
                data: {},
                getItem: function (key) {
                    try {
                        return localStorage.getItem(key);
                    } catch (e) {
                        return this.data[key] || null;
                    }
                },
                setItem: function (key, value) {
                    try {
                        localStorage.setItem(key, value);
                    } catch (e) {
                        this.data[key] = value;
                    }
                },
                removeItem: function (key) {
                    try {
                        localStorage.removeItem(key);
                    } catch (e) {
                        delete this.data[key];
                    }
                }
            };

            // Load search history from storage
            function loadSearchHistory() {
                const historyString = storage.getItem('search_history');
                if (historyString) {
                    try {
                        searchHistory = JSON.parse(historyString);
                    } catch (e) {
                        console.error('Error parsing search history:', e);
                        searchHistory = [];
                    }
                }
            }

            // Save search history to storage
            function saveSearchHistory() {
                storage.setItem('search_history', JSON.stringify(searchHistory));
            }

            // Add search term to history
            function addToSearchHistory(term) {
                if (!term || term.trim() === '') return;

                // Remove existing entry if it exists
                searchHistory = searchHistory.filter(item => item.term !== term);

                // Add new entry at the beginning
                searchHistory.unshift({
                    term: term,
                    timestamp: Date.now()
                });

                // Limit history size
                if (searchHistory.length > MAX_HISTORY_ITEMS) {
                    searchHistory = searchHistory.slice(0, MAX_HISTORY_ITEMS);
                }

                saveSearchHistory();
                updateSearchHistoryUI();
            }

            // Clear search history
            function clearSearchHistory() {
                searchHistory = [];
                saveSearchHistory();
                updateSearchHistoryUI();
            }

            // Format relative time
            function formatRelativeTime(timestamp) {
                const now = Date.now();
                const diff = now - timestamp;

                // If less than a minute
                if (diff < 60 * 1000) {
                    return 'just now';
                }

                // If less than an hour
                if (diff < 60 * 60 * 1000) {
                    const minutes = Math.floor(diff / (60 * 1000));
                    return `${minutes} ${minutes === 1 ? 'minute' : 'minutes'} ago`;
                }

                // If less than a day
                if (diff < 24 * 60 * 60 * 1000) {
                    const hours = Math.floor(diff / (60 * 60 * 1000));
                    return `${hours} ${hours === 1 ? 'hour' : 'hours'} ago`;
                }

                // Otherwise show days
                const days = Math.floor(diff / (24 * 60 * 60 * 1000));
                return `${days} ${days === 1 ? 'day' : 'days'} ago`;
            }

            // Update search history UI
            function updateSearchHistoryUI() {
                if (searchHistory.length === 0) {
                    searchHistoryList.innerHTML = '<div class="search-history-empty">No recent searches</div>';
                    return;
                }

                searchHistoryList.innerHTML = '';

                searchHistory.forEach(item => {
                    const historyItem = document.createElement('div');
                    historyItem.classList.add('search-history-item');

                    historyItem.innerHTML = `
                         <span class="history-text">${item.term}</span>
                         <span class="history-time">${formatRelativeTime(item.timestamp)}</span>
                     `;

                    historyItem.addEventListener('click', () => {
                        searchInput.value = item.term;
                        searchHistoryDropdown.style.display = 'none';
                        filterDatasets();
                    });

                    searchHistoryList.appendChild(historyItem);
                });
            }

            // Toggle search history dropdown
            function toggleSearchHistory() {
                if (searchHistoryDropdown.style.display === 'block') {
                    searchHistoryDropdown.style.display = 'none';
                } else {
                    updateSearchHistoryUI();
                    searchHistoryDropdown.style.display = 'block';
                }
            }

            // Close search history dropdown when clicking outside
            document.addEventListener('click', (event) => {
                if (!searchHistoryDropdown.contains(event.target) &&
                    event.target !== historyToggle &&
                    !historyToggle.contains(event.target)) {
                    searchHistoryDropdown.style.display = 'none';
                }
            });

            // Check for cached data
            const cachedMainData = storage.getItem('gee_main_datasets');
            const cachedCommunityData = storage.getItem('gee_community_datasets');
            const cacheTimestamp = storage.getItem('gee_datasets_timestamp');
            const cacheExpiration = 24 * 60 * 60 * 1000; // 24 hours in milliseconds

            // Load search history
            loadSearchHistory();

            // Initialize from cache or fetch new data
            if (cachedMainData && cachedCommunityData && cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < cacheExpiration) {
                console.log('Loading data from cache');
                mainCatalogDatasets = JSON.parse(cachedMainData);
                communityCatalogDatasets = JSON.parse(cachedCommunityData);

                // Mark each dataset with its catalog source
                mainCatalogDatasets = mainCatalogDatasets.map(dataset => ({
                    ...dataset,
                    catalog_type: 'main'
                }));

                communityCatalogDatasets = communityCatalogDatasets.map(dataset => ({
                    ...dataset,
                    catalog_type: 'community'
                }));

                // Combine datasets
                datasets = [...mainCatalogDatasets, ...communityCatalogDatasets];

                initializeData();
            } else {
                fetchDatasets();
            }

            function fetchDatasets() {
                loadingSpinner.style.display = 'block';

                // Fetch both catalogs
                Promise.all([
                    fetch(mainCatalogUrl).then(response => response.json()),
                    fetch(communityCatalogUrl).then(response => response.json())
                ])
                    .then(([mainData, communityData]) => {
                        // Mark each dataset with its catalog source
                        mainCatalogDatasets = mainData.map(dataset => ({
                            ...dataset,
                            catalog_type: 'main'
                        }));

                        communityCatalogDatasets = communityData.map(dataset => ({
                            ...dataset,
                            catalog_type: 'community'
                        }));

                        // Combine datasets
                        datasets = [...mainCatalogDatasets, ...communityCatalogDatasets];

                        // Cache the fetched data
                        storage.setItem('gee_main_datasets', JSON.stringify(mainCatalogDatasets));
                        storage.setItem('gee_community_datasets', JSON.stringify(communityCatalogDatasets));
                        storage.setItem('gee_datasets_timestamp', Date.now().toString());

                        initializeData();
                        loadingSpinner.style.display = 'none';
                    })
                    .catch(error => {
                        console.warn('Error fetching data, using sample data instead:', error);

                        // Fallback to sample data when fetch fails
                        datasets = getSampleDatasets();
                        mainCatalogDatasets = datasets.filter(d => d.catalog_type === 'main');
                        communityCatalogDatasets = datasets.filter(d => d.catalog_type === 'community');

                        initializeData();
                        loadingSpinner.style.display = 'none';
                    });
            }

            function getSampleDatasets() {
                // Sample datasets that mimic the structure of the actual data
                return [
                    {
                        title: "Global Forest Change",
                        thumbnail: "https://storage.googleapis.com/earthengine-community/examples/forest-change.jpg",
                        thematic_group: "Land Cover & Land Use",
                        docs: "https://example.com/docs/forest-change",
                        sample_code: "https://example.com/code/forest-change",
                        tags: "forest, deforestation, land cover, global",
                        catalog_type: "main"
                    },
                    {
                        title: "Global Surface Water",
                        thumbnail: "https://storage.googleapis.com/earthengine-community/examples/surface-water.jpg",
                        thematic_group: "Hydrology",
                        docs: "https://example.com/docs/surface-water",
                        sample_code: "https://example.com/code/surface-water",
                        tags: "water, hydrology, surface water, global",
                        catalog_type: "main"
                    },
                    {
                        title: "Sentinel-2 Cloud-Free Composite",
                        thumbnail: "https://storage.googleapis.com/earthengine-community/examples/sentinel-2.jpg",
                        thematic_group: "Imagery",
                        docs: "https://example.com/docs/sentinel-2",
                        sample_code: "https://example.com/code/sentinel-2",
                        tags: "sentinel, optical, composite, cloud-free",
                        catalog_type: "community"
                    },
                    {
                        title: "Global Precipitation Measurement",
                        thumbnail: "https://storage.googleapis.com/earthengine-community/examples/precipitation.jpg",
                        thematic_group: "Climate",
                        docs: "https://example.com/docs/precipitation",
                        sample_code: "https://example.com/code/precipitation",
                        tags: "precipitation, rainfall, climate, global",
                        catalog_type: "community"
                    },
                    {
                        title: "MODIS Land Surface Temperature",
                        thumbnail: "https://storage.googleapis.com/earthengine-community/examples/lst.jpg",
                        thematic_group: "Climate",
                        docs: "https://example.com/docs/lst",
                        sample_code: "https://example.com/code/lst",
                        tags: "temperature, LST, MODIS, climate",
                        catalog_type: "main"
                    }
                ];
            }

            function initializeData() {
                // Update catalog counts
                updateCatalogCounts();

                // Extract thematic groups and tags
                extractThematicGroups();
                extractPopularTags();

                // Populate filter panel
                populateFilterPanel();

                // Initialize with random sorting
                shuffleArray(datasets);

                // Apply filters
                filterDatasets();

                // Update pagination
                updatePagination();

                // Update dataset count
                datasetCount.textContent = `${datasets.length} datasets`;
            }

            // Update catalog counts in the UI
            function updateCatalogCounts() {
                allCountBadge.textContent = datasets.length;
                mainCountBadge.textContent = mainCatalogDatasets.length;
                communityCountBadge.textContent = communityCatalogDatasets.length;
            }

            function extractThematicGroups() {
                // Extract unique thematic groups
                const thematicSet = new Set();
                datasets.forEach(dataset => {
                    if (dataset.thematic_group) {
                        thematicSet.add(dataset.thematic_group);
                    }
                });
                allThematicGroups = Array.from(thematicSet).sort();
            }

            function extractPopularTags() {
                // Count tag occurrences
                const tagCounts = {};
                datasets.forEach(dataset => {
                    if (dataset.tags) {
                        // Convert tags to array if it's a string
                        const tagsArray = Array.isArray(dataset.tags)
                            ? dataset.tags
                            : typeof dataset.tags === 'string'
                                ? dataset.tags.split(',').map(tag => tag.trim())
                                : [];

                        tagsArray.forEach(tag => {
                            if (tag) {
                                tagCounts[tag] = (tagCounts[tag] || 0) + 1;
                            }
                        });
                    }
                });

                // Sort tags by frequency
                allTags = Object.keys(tagCounts)
                    .sort((a, b) => tagCounts[b] - tagCounts[a])
                    .slice(0, 20); // Get top 20 tags
            }

            function populateFilterPanel() {
                // Clear existing filters
                thematicFilters.innerHTML = '';
                tagFilters.innerHTML = '';

                // Add thematic group checkboxes
                allThematicGroups.forEach(group => {
                    const checkbox = document.createElement('div');
                    checkbox.classList.add('filter-checkbox');
                    checkbox.innerHTML = `
                         <input type="checkbox" id="theme-${group.replace(/\s+/g, '-').replace(/[&]/g, 'and')}" data-group="${group}">
                         <label for="theme-${group.replace(/\s+/g, '-').replace(/[&]/g, 'and')}">${group}</label>
                     `;
                    thematicFilters.appendChild(checkbox);
                });

                // Add tag checkboxes
                allTags.forEach(tag => {
                    const checkbox = document.createElement('div');
                    checkbox.classList.add('filter-checkbox');
                    checkbox.innerHTML = `
                         <input type="checkbox" id="tag-${tag.replace(/\s+/g, '-')}" data-tag="${tag}">
                         <label for="tag-${tag.replace(/\s+/g, '-')}">${tag}</label>
                     `;
                    tagFilters.appendChild(checkbox);
                });

                // Add event listeners to checkboxes
                document.querySelectorAll('.filter-checkbox input').forEach(checkbox => {
                    checkbox.addEventListener('change', () => {
                        if (checkbox.dataset.group) {
                            if (checkbox.checked) {
                                activeThematicFilters.push(checkbox.dataset.group);
                            } else {
                                activeThematicFilters = activeThematicFilters.filter(g => g !== checkbox.dataset.group);
                            }
                        } else if (checkbox.dataset.tag) {
                            if (checkbox.checked) {
                                activeTagFilters.push(checkbox.dataset.tag);
                            } else {
                                activeTagFilters = activeTagFilters.filter(t => t !== checkbox.dataset.tag);
                            }
                        }
                        filterDatasets();
                        updatePagination();
                    });
                });
            }

            function shuffleArray(array) {
                for (let i = array.length - 1; i > 0; i--) {
                    const j = Math.floor(Math.random() * (i + 1));
                    [array[i], array[j]] = [array[j], array[i]];
                }
            }

            function filterDatasets() {
                const searchTerm = searchInput.value.toLowerCase();

                // Save to search history if not empty
                if (searchTerm && searchTerm.trim() !== '') {
                    addToSearchHistory(searchTerm);
                }

                // First filter by catalog type
                let initialDatasets = datasets;
                if (activeCatalogFilter === 'main') {
                    initialDatasets = mainCatalogDatasets;
                } else if (activeCatalogFilter === 'community') {
                    initialDatasets = communityCatalogDatasets;
                }

                // Then filter by search term
                filteredDatasets = initialDatasets.filter(dataset => {
                    // Basic fields search
                    const basicMatch = (
                        dataset.title.toLowerCase().includes(searchTerm) ||
                        (dataset.thematic_group && dataset.thematic_group.toLowerCase().includes(searchTerm))
                    );

                    if (basicMatch) return true;

                    // Tags search if tags exist
                    if (dataset.tags) {
                        // Handle tags as string or array
                        if (typeof dataset.tags === 'string') {
                            return dataset.tags.toLowerCase().includes(searchTerm);
                        } else if (Array.isArray(dataset.tags)) {
                            return dataset.tags.some(tag =>
                                String(tag).toLowerCase().includes(searchTerm));
                        }
                    }

                    return false;
                });

                // Then filter by thematic group
                if (activeThematicFilters.length > 0) {
                    filteredDatasets = filteredDatasets.filter(dataset =>
                        dataset.thematic_group && activeThematicFilters.includes(dataset.thematic_group)
                    );
                }

                // Then filter by tags
                if (activeTagFilters.length > 0) {
                    filteredDatasets = filteredDatasets.filter(dataset => {
                        if (!dataset.tags) return false;

                        const tagsArray = Array.isArray(dataset.tags)
                            ? dataset.tags
                            : typeof dataset.tags === 'string'
                                ? dataset.tags.split(',').map(tag => tag.trim())
                                : [];

                        return activeTagFilters.some(filterTag =>
                            tagsArray.some(datasetTag => datasetTag === filterTag)
                        );
                    });
                }

                // Apply sorting
                sortDatasets();

                datasetCount.textContent = `${filteredDatasets.length} datasets`;
                currentPage = 1;
                displayCurrentPage();
                updatePagination();
            }

            function sortDatasets() {
                const sortMethod = sortSelect.value;

                switch (sortMethod) {
                    case 'title-asc':
                        filteredDatasets.sort((a, b) => a.title.localeCompare(b.title));
                        break;
                    case 'title-desc':
                        filteredDatasets.sort((a, b) => b.title.localeCompare(a.title));
                        break;
                    case 'group':
                        filteredDatasets.sort((a, b) => {
                            const groupA = a.thematic_group || '';
                            const groupB = b.thematic_group || '';
                            return groupA.localeCompare(groupB) || a.title.localeCompare(b.title);
                        });
                        break;
                    case 'random':
                        shuffleArray(filteredDatasets);
                        break;
                }
            }

            function displayCurrentPage() {
                const startIndex = (currentPage - 1) * itemsPerPage;
                const endIndex = startIndex + itemsPerPage;
                const currentPageItems = filteredDatasets.slice(startIndex, endIndex);

                datasetContainer.innerHTML = '';

                if (currentPageItems.length === 0) {
                    datasetContainer.innerHTML = '<p class="col-span-full text-center">No datasets found matching your search.</p>';
                    return;
                }

                if (currentView === 'grid') {
                    datasetContainer.className = 'grid-view';
                    displayGridView(currentPageItems);
                } else {
                    datasetContainer.className = 'list-view';
                    displayListView(currentPageItems);
                }
            }

            // Updated grid view display with fixed sizes
            function displayGridView(items) {
                items.forEach(dataset => {
                    const card = document.createElement('div');
                    card.classList.add('card', 'border', 'rounded', 'flex', 'flex-col', 'dataset-card');

                    // Process tags for display
                    let tagsHTML = '';
                    let tagsArray = [];
                    if (dataset.tags) {
                        // Convert tags to array if it's a string
                        tagsArray = Array.isArray(dataset.tags)
                            ? dataset.tags
                            : dataset.tags.split(',').map(tag => tag.trim());

                        if (tagsArray.length > 0) {
                            tagsHTML = '<div class="tags-container">';
                            // Show all tags in the HTML, visibility will be controlled by CSS
                            tagsArray.forEach(tag => {
                                tagsHTML += `<span class="tag cursor-pointer" onclick="document.getElementById('search').value='${tag}'; document.getElementById('search').dispatchEvent(new Event('input'));">${tag}</span>`;
                            });
                            tagsHTML += '</div>';

                            // Add "more tags" indicator only if there are more than 8 tags
                            if (tagsArray.length > 8) {
                                tagsHTML += `<span class="more-tags-indicator">+${tagsArray.length - 8} more</span>`;
                            }
                        }
                    }

                    card.innerHTML = `
            <h2 class="card-title text-base font-medium">${dataset.title}</h2>
            <p class="card-thematic text-sm text-gray-500 dark:text-gray-400">${dataset.thematic_group || ''}</p>
            <div class="card-image-container bg-gray-200 dark:bg-gray-700 my-2">
                ${dataset.catalog_type === 'main' ?
                            `<img src="https://i.imgur.com/m0Lki0L.png" alt="Main Catalog" class="catalog-icon" title="Main Catalog">` :
                            ''}
                <img
                    data-src="${dataset.thumbnail}"
                    alt="${dataset.title}"
                    class="lazy-image"
                    onerror="this.onerror=null; this.src='/api/placeholder/256/256'; this.classList.add('loaded');">
            </div>
            <div class="card-buttons">
                ${dataset.docs ? `<a href="${dataset.docs}" target="_blank" class="btn border p-2 flex-1 text-center">Docs</a>` : ''}
                ${dataset.sample_code ? `<a href="${dataset.sample_code}" target="_blank" class="btn border p-2 flex-1 text-center">Code</a>` : ''}
            </div>
            <div class="card-tags">
                ${tagsHTML}
            </div>
        `;

                    datasetContainer.appendChild(card);
                });

                // Initialize lazy loading for grid view images
                initLazyLoading();
            }

            // Updated list view with better text handling
            function displayListView(items) {
                items.forEach(dataset => {
                    const listItem = document.createElement('div');
                    listItem.classList.add('list-item', 'border', 'rounded');

                    // Process tags for list view
                    let tagsHTML = '';
                    if (dataset.tags) {
                        // Convert tags to array if it's a string
                        const tagsArray = Array.isArray(dataset.tags)
                            ? dataset.tags
                            : dataset.tags.split(',').map(tag => tag.trim());

                        if (tagsArray.length > 0) {
                            tagsHTML = '<div class="list-tags">';
                            // In list view, show up to 4 tags
                            const visibleTags = tagsArray.slice(0, 4);
                            visibleTags.forEach(tag => {
                                tagsHTML += `<span class="tag cursor-pointer" onclick="document.getElementById('search').value='${tag}'; document.getElementById('search').dispatchEvent(new Event('input'));">${tag}</span>`;
                            });

                            // Add a more tags indicator if needed
                            if (tagsArray.length > 4) {
                                tagsHTML += `<span class="tag more-tag">+${tagsArray.length - 4}</span>`;
                            }

                            tagsHTML += '</div>';
                        }
                    }

                    listItem.innerHTML = `
            <div class="bg-gray-200 dark:bg-gray-700 rounded-md overflow-hidden w-20 h-20 relative">
                ${dataset.catalog_type === 'main' ?
                            `<img src="https://i.imgur.com/m0Lki0L.png" alt="Main Catalog" class="catalog-icon" title="Main Catalog">` :
                            ''}
                <img
                    data-src="${dataset.thumbnail}"
                    alt="${dataset.title}"
                    class="lazy-image"
                    onerror="this.onerror=null; this.src='/api/placeholder/80/80'; this.classList.add('loaded');">
            </div>
            <div class="flex flex-col">
                <h2 class="list-title text-base font-medium" title="${dataset.title}">${dataset.title}</h2>
                <p class="list-thematic text-sm text-gray-500 dark:text-gray-400" title="${dataset.thematic_group || ''}">${dataset.thematic_group || ''}</p>
                ${tagsHTML}
            </div>
            <div class="buttons flex gap-2">
                ${dataset.docs ? `<a href="${dataset.docs}" target="_blank" class="btn border p-2">Docs</a>` : ''}
                ${dataset.sample_code ? `<a href="${dataset.sample_code}" target="_blank" class="btn border p-2">Code</a>` : ''}
            </div>
        `;

                    datasetContainer.appendChild(listItem);
                });

                // Initialize lazy loading for the current page
                initLazyLoading();
            }

            function initLazyLoading() {
                const lazyImages = document.querySelectorAll('.lazy-image');

                if ('IntersectionObserver' in window) {
                    const imageObserver = new IntersectionObserver((entries, observer) => {
                        entries.forEach(entry => {
                            if (entry.isIntersecting) {
                                const img = entry.target;
                                img.src = img.dataset.src;

                                img.onload = () => {
                                    img.classList.add('loaded');
                                };

                                img.onerror = () => {
                                    // Set appropriate fallback image based on parent container size
                                    const parent = img.parentElement;
                                    const width = parent.offsetWidth || 256;
                                    const height = parent.offsetHeight || 256;
                                    img.src = createFallbackImageUrl(width, height);
                                    img.classList.add('loaded');
                                };

                                imageObserver.unobserve(img);
                            }
                        });
                    });

                    lazyImages.forEach(img => imageObserver.observe(img));
                } else {
                    // Fallback for browsers that don't support IntersectionObserver
                    lazyImages.forEach(img => {
                        img.src = img.dataset.src;

                        img.onload = () => {
                            img.classList.add('loaded');
                        };

                        img.onerror = () => {
                            const parent = img.parentElement;
                            const width = parent.offsetWidth || 256;
                            const height = parent.offsetHeight || 256;
                            img.src = createFallbackImageUrl(width, height);
                            img.classList.add('loaded');
                        };
                    });
                }
            }

            function updatePagination() {
                const totalPages = Math.ceil(filteredDatasets.length / itemsPerPage);
                paginationContainer.innerHTML = '';

                if (totalPages <= 1) return;

                // Add first page button
                if (currentPage > 1) {
                    const firstButton = createPaginationButton('«', () => {
                        currentPage = 1;
                        displayCurrentPage();
                        updatePagination();
                        window.scrollTo(0, 0);
                    });
                    paginationContainer.appendChild(firstButton);
                }

                // Add prev button
                if (currentPage > 1) {
                    const prevButton = createPaginationButton('‹', () => {
                        currentPage--;
                        displayCurrentPage();
                        updatePagination();
                        window.scrollTo(0, 0);
                    });
                    paginationContainer.appendChild(prevButton);
                }

                // Determine page numbers to show
                let startPage = Math.max(1, currentPage - 2);
                let endPage = Math.min(totalPages, startPage + 4);

                if (endPage - startPage < 4) {
                    startPage = Math.max(1, endPage - 4);
                }

                // Show start ellipsis if needed
                if (startPage > 1) {
                    paginationContainer.appendChild(createPaginationButton('...', null, false, true));
                }

                // Add page number buttons
                for (let i = startPage; i <= endPage; i++) {
                    const button = createPaginationButton(i, () => {
                        currentPage = i;
                        displayCurrentPage();
                        updatePagination();
                        window.scrollTo(0, 0);
                    }, i === currentPage);

                    paginationContainer.appendChild(button);
                }

                // Show end ellipsis if needed
                if (endPage < totalPages) {
                    paginationContainer.appendChild(createPaginationButton('...', null, false, true));
                }

                // Add next button
                if (currentPage < totalPages) {
                    const nextButton = createPaginationButton('›', () => {
                        currentPage++;
                        displayCurrentPage();
                        updatePagination();
                        window.scrollTo(0, 0);
                    });
                    paginationContainer.appendChild(nextButton);
                }

                // Add last page button
                if (currentPage < totalPages) {
                    const lastButton = createPaginationButton('»', () => {
                        currentPage = totalPages;
                        displayCurrentPage();
                        updatePagination();
                        window.scrollTo(0, 0);
                    });
                    paginationContainer.appendChild(lastButton);
                }
            }

            function createPaginationButton(text, onClick, isActive = false, isDisabled = false) {
                const button = document.createElement('button');
                button.textContent = text;

                if (isActive) {
                    button.classList.add('active');
                }

                if (isDisabled) {
                    button.disabled = true;
                    button.classList.add('cursor-default', 'opacity-50');
                } else if (onClick) {
                    button.addEventListener('click', onClick);
                }

                return button;
            }

            // Event Listeners
            // Catalog filter change
            catalogFilterInputs.forEach(input => {
                input.addEventListener('change', () => {
                    activeCatalogFilter = input.value;
                    filterDatasets();
                });
            });

            // Search with debounce
            searchInput.addEventListener('input', () => {
                loadingSpinner.style.display = 'block';

                if (searchTimeout) {
                    clearTimeout(searchTimeout);
                }

                searchTimeout = setTimeout(() => {
                    filterDatasets();
                    loadingSpinner.style.display = 'none';
                }, 300); // Wait 300ms after typing stops
            });

            // Theme toggle
            themeToggle.addEventListener('click', () => {
                document.body.classList.toggle('dark');
                themeIcon.textContent = document.body.classList.contains('dark') ? 'dark_mode' : 'light_mode';

                // Store theme preference
                storage.setItem('theme_preference', document.body.classList.contains('dark') ? 'dark' : 'light');
            });

            // Filter panel toggle
            filterToggle.addEventListener('click', () => {
                filterPanel.classList.toggle('collapsed');
            });

            // View toggle
            gridViewBtn.addEventListener('click', () => {
                if (currentView !== 'grid') {
                    currentView = 'grid';
                    gridViewBtn.classList.add('active');
                    listViewBtn.classList.remove('active');
                    displayCurrentPage();

                    // Initialize lazy loading after switching views
                    setTimeout(() => initLazyLoading(), 50);

                    // Save view preference
                    storage.setItem('view_preference', 'grid');
                }
            });

            listViewBtn.addEventListener('click', () => {
                if (currentView !== 'list') {
                    currentView = 'list';
                    listViewBtn.classList.add('active');
                    gridViewBtn.classList.remove('active');
                    displayCurrentPage();

                    // Initialize lazy loading after switching views
                    setTimeout(() => initLazyLoading(), 50);

                    // Save view preference
                    storage.setItem('view_preference', 'list');
                }
            });

            // Sort change
            sortSelect.addEventListener('change', () => {
                sortDatasets();
                displayCurrentPage();

                // Save sort preference
                storage.setItem('sort_preference', sortSelect.value);
            });

            // History toggle click event
            historyToggle.addEventListener('click', (event) => {
                event.stopPropagation();
                toggleSearchHistory();
            });

            // Clear history button click event
            clearHistoryBtn.addEventListener('click', (event) => {
                event.stopPropagation();
                clearSearchHistory();
            });

            // Load saved preferences
            const savedTheme = storage.getItem('theme_preference');
            if (savedTheme === 'dark') {
                document.body.classList.add('dark');
                themeIcon.textContent = 'dark_mode';
            }

            const savedView = storage.getItem('view_preference');
            if (savedView === 'list') {
                currentView = 'list';
                listViewBtn.classList.add('active');
                gridViewBtn.classList.remove('active');
            }

            const savedSort = storage.getItem('sort_preference');
            if (savedSort) {
                sortSelect.value = savedSort;
            }
        });
                </script>
    </body>

    </html>
